from django.shortcuts import render

from django.http import JsonResponse
from django.views import View
# Create your views here.
#注意User的导包路径
from .models import User, Address
import json,re
from django_redis import get_redis_connection
from django import http
from meiduo_mall.utils.secret import SecretOauth

from carts.utils import merge_cart_cookie_to_redis



# from django.contrib.auth import login


#判断用户名是否重复注册
class UsernameCountView(View):
    """判断用户名是否重复注册"""
    def get(self, request, username):
        """判断用户名是否重复"""
        try:
            count = User.objects.filter(username=username).count()
        except Exception as e:
            return JsonResponse({'code': 400, 'errmsg': '访问数据库失败'})

        #返回结果
        return JsonResponse({'code': 0, 'errmsg': 'ok', 'count': count})


#判断手机号是否重复注册
class MobileCountView(View):
    def get(self, request, mobile):
        #1、查询mobile在mysql中的个数

        count = User.objects.filter(mobile=mobile).count()

        #2、返回结果
        return JsonResponse({'code': 0, 'errmsg':'ok', 'count': count})


#用户注册
class RegisterView(View):
    def post(self, request):
        """接收参数，保存到数据库"""
        #1、接收参数，请求体中的ＪＳＯＮ数据，request.body
        data = json.loads(request.body.decode())
        #提取参数
        username = data.get('username')
        password = data.get('password')
        password2 = data.get('password2')
        mobile = data.get('mobile')
        allow = data.get('allow', False)
        sms_code = data.get('sms_code')
        #2、参数校验
        #整体参数校验是否为空
        if not all([username, password, password2, mobile, sms_code]):
            return JsonResponse({'code': 400, 'errmsg': '缺少必传参数！'})

        #username校验
        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return JsonResponse({'code': 400, 'errmsg': 'username格式有误！'})

        #password校验
        if not re.match(r'^[a-zA-Z0-9_-]{8,20}$', password):
            return JsonResponse({'code': 400, 'errmsg': 'password格式有误！'})
        #password和password2校验
        if password != password2:
            return JsonResponse({'code': 400, 'errmsg': '两次输入不对！'})

        #mobile校验
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return JsonResponse({'code': 400, 'errmsg': 'mobile格式有误！'})
        #allow校验
        if not allow:
            return JsonResponse({'code': 400, 'errmsg': '请求勾选同意协议'})

        #短信验证码格式
        if not re.match(r'^\d{6}$', sms_code):
            return JsonResponse({'code': 400, 'errmsg': '短信验证码格式有误！'})

        #请求勾选同意协议
        if not isinstance(allow, bool):
            return JsonResponse({'code': 400, 'errmsg': 'allow格式有误'})
        #短信验证校验
        conn = get_redis_connection('verify_code')
        sms_code_from_redis = conn.get('sms_%s' % mobile)
        if not sms_code:
            return JsonResponse({'code': 400, 'errmsg': '短信验证码过期'})

        if sms_code != sms_code_from_redis.decode():
            return JsonResponse({'code': 400, 'errmsg': '短信验证码有误！'})


        #3、业务数据处理
        try:
            user = User.objects.create_user(username=username,
                                            password=password,
                                            mobile=mobile)
        except Exception as e:
            print(e)
            return JsonResponse({'code': 400, 'errmsg': '注册失败！'})

        #实现状态保持
        login(request, user, backend='django.contrib.auth.backends.ModelBackend')
        #4、构建响应
        response =  JsonResponse({'code': 0, 'errmsg': 'ok'})
        response.set_cookie('username', user.username, max_age=3600 * 24 * 14)
        return response


from django.contrib.auth import login, authenticate
#用户名登录
class LoginView(View):
    def post(self, request):
        """实现登录接口"""
        #1、接收参数
        data = json.loads(request.body.decode())
        username = data.get('username')
        password = data.get('password')
        remembered = data.get('remembered')
        #2、校验（整体＋单个）
        if not all([username, password]):
            return JsonResponse({'code': 400, 'errmsg': '缺少必传参数'})
        # 2.2、约束校验
        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return JsonResponse({
                    'code': 400,
                    'errmsg': '用户名格式有误',
            }, status=400)

        if not re.match(r'^[a-zA-Z0-9]{8,20}$', password):
            return JsonResponse({
                    'code': 400,
                    'errmsg': '密码格式有误',
            }, status=400)

        #3、验证是否能够登录
        user = authenticate(request, username=username, password=password)
        #4、判断是否为空，如果为空，返回
        if not user:
            return JsonResponse({'code': 400, 'errmsg': '用户名或者密码错误！'})
        #5、状态保持
        login(request, user)
        #6、判断是否记住用户
        if remembered != True:
            request.session.set_expiry(0)
        else:
            request.session.set_expiry(None)
        #7、构建响应
        response = JsonResponse({'code': 0, 'errmsg': 'ok'})
        response.set_cookie('username', user.username, max_age=3600 * 24 * 14)
        #cookie和redis数据合并
        response = merge_cart_cookie_to_redis(request, response)
        return response


#退出登录
from django.contrib.auth import logout
class LogoutView(View):
    def delete(self, request):
        """实现退出登录逻辑"""
        #清理session
        logout(request)
        #创建response对象
        response = JsonResponse({'code': 0, 'errmsg': 'ok'})
        #调用对象的delete_cookie方法，清楚cookie
        response.delete_cookie('username')
        #构建响应
        return response


from meiduo_mall.utils.views import LoginRequiredJSONMixin
#用户中心－类视图
class UserInfoView(LoginRequiredJSONMixin, View):
    def get(self, request):
        #1、获取已经登陆的用户
        user = request.user

        return JsonResponse({
            'code': 0,
            'errmsg': 'ok',
            'info_data': {
                'username': user.username,
                'mobile': user.mobile,
                'email': user.email,
                'email_active': user.email_active
            }
        })


from celery_tasks.email.tasks import send_verify_email
from users.utils import generate_verify_email_url
#添加邮箱
class EmailView(LoginRequiredJSONMixin, View):
    def put(self, request):
        #接收参数
        data = json.loads(request.body.decode())
        email = data.get('email')
        #校验参数
        if not email:
            return JsonResponse({'code': 400,
                            'errmsg':'缺少email参数'})
        if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
            return JsonResponse({'code': 400,
                            'errmsg': '参数email有误'})

        #业务数据处理
        user = request.user
        user.email = email
        user.save()
        # TODO: 发送验证邮件
        # verify_url分为2个部分：
        # (1)、固定的验证请求前缀：http://www.meiduo.site:8080/success_verify_email.html?token=
        # (2)、查询字符串参数： ?token=<是一个字符串，该字符串是加密后的用户数据>
        # 需要生成记录当前登陆用户信息的token，作为verify_url查询字符串的拼接
        verify_url = generate_verify_email_url(request)
        send_verify_email.delay(email, verify_url=verify_url)


        #构建响应
        return JsonResponse({'code': 0, 'errmsg': 'ok'})


#验证邮箱
class VerifyEmailView(View):
    def put(self, request):
        #1、接收token
        token = request.GET.get('token')
        if not token:
            return JsonResponse({'code': 400, 'errmsg': '缺少token'})
        #2、解密,业务数据处理
        auth = SecretOauth()
        user_info = auth.loads(token)
        if user_info is None:
            return JsonResponse({'code': 400, 'ermsg': 'token无效'})
        user_id = user_info.get('user_id')
        email = user_info.get('email')

        # 3.2、激活邮件 —— 把email_active设置为True
        try:
            user = User.objects.get(pk=user_id)
            user.email_active = True
            user.save()
        except Exception as e:
            return JsonResponse({'code': 400, 'errmsg': '激活失败'})
        #构建响应
        return JsonResponse({'code': 0, 'errmsg': '激活成功！'})


#新增收货地址
class CreateAddressView(LoginRequiredJSONMixin, View):
    def post(self, request):
        #获取地址个数
        user = request.user
        count = Address.objects.filter(user=user,
                        is_deleted=False).count()
        #判断是否超过地址上限，最多２０个
        if count >= 20:
            return JsonResponse({'code': 400, 'errmsg': '超过地址数量上限'})
        #接收参数
        data = json.loads(request.body.decode())
        receiver = data.get('receiver')
        province_id = data.get('province_id')
        city_id = data.get('city_id')
        district_id = data.get('district_id')
        place = data.get('place')
        mobile = data.get('mobile')
        tel = data.get('tel')
        email = data.get('email')
        #校验参数
        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return JsonResponse({'code': 400, 'errmsg': '缺少必传参数'})

        if not re.match(r'^\w{1,20}$', receiver):
            return JsonResponse({'code': 400, 'errmsg': '参数receiver有误'})

        if not re.match(r'^\w{1,50}$', place):
            return JsonResponse({'code': 400, 'errmsg': '参数place有误'})

        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return JsonResponse({'code': 400, 'errmsg': '参数mobile有误！'})

        if tel:
            if not re.match(r'^\w{1,20}$', tel):
                return JsonResponse({'code': 400, 'errmsg': '参数tel有误'})
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return JsonResponse({'code': 400, 'errmsg': '参数email有误'})
            if len(email) > 30:
                return JsonResponse({'code': 400, 'errmsg': '邮箱长度有误'})

        #保存地址信息
        try:
            address = Address.objects.create(
                user=user,
                title = receiver,
                receiver = receiver,
                province_id = province_id,
                city_id = city_id,
                district_id = district_id,
                place = place,
                mobile = mobile,
                tel = tel or "",
                email = email or ""
            )
        #设置默认地址
            if not user.default_address:
                user.default_address = address
                user.save()

        except Exception as e:
            return JsonResponse({'code': 400, 'errmsg': '新增地址失败！'})
        #新增地址成功，将新增的地址响应给前端实现局部刷新
        address_dict = {
            "id": address.id,
            "title": address.title,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }
        #响应保存结果
        return JsonResponse({'code': 0, 'errmsg': '新增地址成功！', 'address':address_dict})


#用户收货地址
class AddressView(LoginRequiredJSONMixin, View):
    def get(self, request):
        user = request.user
        #提供地址管理界面
        address_queryset = Address.objects.filter(user=user, is_deleted=False)
        #获取所有的地址
        addresses = []
        #创建空的列表
        #遍历
        for address in address_queryset:
            address_dict = {
                "id": address.id,
                "title": address.title,
                "receiver": address.receiver,
                "province": address.province.name,
                "city": address.city.name,
                "district": address.district.name,
                "place": address.place,
                "mobile": address.mobile,
                "tel": address.tel,
                "email": address.email
            }
            if address.id == user.default_address_id:
                addresses.insert(0, address_dict)
            else:
                addresses.append(address_dict)
        #获取默认地址id
        # default_id = request.user.default_address_id
        return JsonResponse({'code': 0,
                             'errmsg': 'ok',
                             'addresses':addresses,
                             'default_address_id':user.default_address_id})


#修改和删除地址
class UpdateDestroyAddressView(LoginRequiredJSONMixin, View):

    #修改地址
    def put(self, request, address_id):
        # 接收参数
        json_dict = json.loads(request.body.decode())
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')

        # 校验参数
        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return JsonResponse({'code': 400,
                                      'errmsg': '缺少必传参数'})
        if not re.match(r'^\w{1,20}$', receiver):
            return JsonResponse({'code': 400, 'errmsg': '参数receiver有误'})

        if not re.match(r'^\w{1,50}$', place):
            return JsonResponse({'code': 400, 'errmsg': '参数place有误'})


        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return JsonResponse({'code': 400,
                                      'errmsg': '参数mobile有误'})

        if tel:
            if not re.match(r'^\w{1,20}$', tel):
                return JsonResponse({'code': 400,
                                          'errmsg': '参数tel有误'})
        if email:
            if not re.match(r'^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$', email):
                return JsonResponse({'code': 400, 'errmsg': '参数email有误'})
            if len(email) > 30:
                return JsonResponse({'code': 400, 'errmsg': '邮箱长度有误'})

        # 判断地址是否存在,并更新地址信息
        try:
            address = Address.objects.get(pk=address_id)

            address.receiver = receiver
            address.province_id = province_id
            address.city_id = city_id
            address.district_id = district_id
            address.place = place
            address.mobile = mobile
            address.tel = tel or ""
            address.email = email or ""

            address.save()  # 写入数据库


        except Exception as e:
            return JsonResponse({'code': 400,
                                      'errmsg': '更新地址失败'})

        # 构造响应数据
        address_dict = {
            "id": address.id,
            "title": address.title,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }

        # 响应更新地址结果
        return JsonResponse({'code': 0,
                            'errmsg': '更新地址成功',
                            'address': address_dict})


    #删除地址
    def delete(self, request, address_id):
        user = request.user
        try:
            #查询要删除的地址
            address = Address.objects.get(pk=address_id)
            #将地址逻辑删除设置为True
            address.is_deleted = True
            address.save()
            # 如果删除的地址刚好是用户的默认地址，需要把用户默认地址设置为None
            if address.id == user.default_address_id:
                user.default_address = None
                user.save()
        except Exception as e:
            return JsonResponse({'code': 400, 'errmsg': '删除地址失败'})
            #响应删除地址结果
        return JsonResponse({'code': 0, 'errmsg': '删除地址成功'})


#设置默认地址
class DefaultAddressView(LoginRequiredJSONMixin, View):
    def put(self, request, address_id):
        user = request.user
        try:
            #接收参数，查询地址
            address = Address.objects.get(pk=address_id, is_deleted=False)
            #设置地址为默认地址
            user.default_address = address
            user.save()
        except Exception as e:
            return JsonResponse({'code': 400, 'errmsg': '设置默认地址失败'})
            #响应设置默认地址结果
        return JsonResponse({'code': 0, 'errmsg': '设置默认地址成功！'})


#设置地址标题
class UpdateTitleAddressView(LoginRequiredJSONMixin, View):
    def put(self, request, address_id):
        # 接收参数：地址标题
        user = request.user
        data = json.loads(request.body.decode())
        title = data.get('title')

        # 2、校验参数
        if not title:
            return JsonResponse({'code': 400, 'errmsg': '参数缺失'})
        if len(title) > 20:
            return JsonResponse({'code': 400, 'errmsg': '参数有误'})

        # 3、业务数据处理 —— 更新地址的title字段
        try:
            address = Address.objects.get(pk=address_id, is_deleted=False)
            address.title = title
            address.save()
        except Exception as e:

            return JsonResponse({'code': 400,
                                      'errmsg': '设置地址标题失败'})

        # 4.响应删除地址结果
        return JsonResponse({'code': 0,
                                  'errmsg': '设置地址标题成功'})


#修改密码
class ChangePasswordView(LoginRequiredJSONMixin, View):
    def put(self, request):
        # 接收参数
        user = request.user
        data = json.loads(request.body.decode())
        old_password = data.get('old_password')
        new_password = data.get('new_password')
        new_password2 = data.get('new_password2')

        # 校验参数
        if not all([old_password, new_password, new_password2]):
            return JsonResponse({'code': 400,
                                'errmsg': '缺少必传参数'})


        #新密码格式是否一样
        if not re.match(r'^[0-9A-Za-z]{8,20}$', new_password):
            return JsonResponse({'code': 400,
                                      'errmsg': '密码最少8位,最长20位'})
        #两次数据是否一样
        if new_password != new_password2:
            return JsonResponse({'code': 400,
                                      'errmsg': '两次输入密码不一致'})

        #旧密码是否输入正确
        result = user.check_password(old_password)
        if not result:
            return JsonResponse({'code': 400,
                                 'errmsg': '原始密码不正确'})

        # 修改密码
        try:
            user.set_password(new_password)
            user.save()
        except Exception as e:
            return JsonResponse({'code': 400,
                                      'errmsg': '修改密码失败'})

        # 清理状态保持信息
        logout(request)

        response = JsonResponse({'code': 0,
                                      'errmsg': 'ok'})

        response.delete_cookie('username')

        # # 响应密码修改结果：重定向到登录界面
        return response


from goods.models import SKU
from django.utils import timezone
from goods.models import SKU,GoodsVisitCount
#用户浏览记录
class UserBrowseHistory(LoginRequiredJSONMixin, View):

    #保存用户浏览记录
    def post(self, request):
        #接收参数
        user = request.user
        json_dict = json.loads(request.body.decode())
        sku_id = json_dict.get('sku_id')
        #校验参数
        try:
            sku = SKU.objects.get(pk=sku_id,
                                  is_launched=True)
        except Exception as e:
            return JsonResponse({
                'code': 0,
                'errmsg': 'ok'
            })
        #保存用户浏览数据
        conn = get_redis_connection('history')
        p = conn.pipeline()

        #先去重，再存储，最后截取，执行管道

        p.lrem('history_%s'%user.id, 0, sku_id)
        p.lpush('history_%s' % user.id, sku_id)
        p.ltrim('history_%s'%user.id, 0, 4)
        p.execute()

        # TODO: 记录该sku商品分类访问量
        category = sku.category
        cur_0_time = timezone.localtime().replace(hour=0, minute=0, second=0)

        try:
            cate_visit = GoodsVisitCount.objects.get(
                category=category,
                create_time__gte=cur_0_time
            )
        except GoodsVisitCount.DoesNotExist as e:
            # 记录不存在，则新建，count初始化为1
            cate_visit = GoodsVisitCount.objects.create(
                count=1,
                category=category
            )
        else:
            # 记录存在则累加count
            cate_visit.count += 1
            cate_visit.save()


        #响应结果
        return JsonResponse({'code': 0,
                             'errmsg': 'OK'})


    #获取用户浏览记录
    def get(self, request):
        #获取redis存储的sku_id列表信息
        user = request.user
        # 2、校验参数
        # 3、业务处理 —— 从redis读历史记录，在从mysql读详细信息
        # 3.1、读取redis历史(访问的sku_id)
        conn = get_redis_connection('history')
        sku_ids = conn.lrange(
            'history_%s' % user.id,
            0, -1
        )
        skus = SKU.objects.filter(
            id__in = sku_ids
        )
        #根据sku_id列表数据，查询出商品sku信息
        sku_list = []
        for sku in skus:
            sku_list.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'price': sku.price
            })
        #构建响应
        return JsonResponse({'code': 0,
                             'errmsg': 'OK',
                             'skus': sku_list})